package threadUtils.demo08;

import java.util.LinkedList;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

/**
 * Condition锁在实现生产者，消费者场景很普遍
 */
public class ConditionProducerAndConsumer {

    private static final int MAX_CAPACITY = 100; // 最大容量
    private static final ReentrantLock reentrantLock = new ReentrantLock(); // Lock显示锁
    private static final Condition producerLock = reentrantLock.newCondition();
    private static final Condition consumerLock = reentrantLock.newCondition();
    private static final LinkedList<Integer> list = new LinkedList<>();
    private static int i = 0;

    // 生产者
    private static void producer() {
        reentrantLock.lock();
        try {

            while (list.size() >= MAX_CAPACITY) { // 当数据已满，生产者进入阻塞状态
                producerLock.await();
            }
            i++;
            list.add(i);
            System.out.println(Thread.currentThread().getName() + " Producer ->" + i);
            consumerLock.signalAll(); // 唤醒消费者
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            reentrantLock.unlock();
        }
    }

    // 消费者
    private static void consumer() {
        reentrantLock.lock();
        try {
            while (list.isEmpty()) { // 当数据为空值，消费者进入阻塞状态
                consumerLock.await();
            }
            Integer integer = list.removeFirst(); // 消费链表数据
            System.out.println(Thread.currentThread().getName() + " Consumer ->" + integer);
            producerLock.signalAll(); // 唤醒生产者
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            reentrantLock.unlock();
        }

    }

    public static void main(String[] args) {

        for (int i = 0; i < 10; i++) {
            new Thread(() -> {
                for (;;)
                {
                    producer();
                    sleep();
                }
            }, "P-" + i).start();
        }

        for (int i = 0; i < 5; i++) {
            new Thread(() -> {
                for (;;)
                {
                    consumer();
                    sleep();
                }
            }, "C-" + i).start();
        }
    }

    public static void sleep() {
        try {
            TimeUnit.MICROSECONDS.sleep(50);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
